# -*- coding: UTF-8 -*-
"""
@auth:buxiangjie
@date:2022/2/10 10:22
@describe: 
"""
import json
import os
import traceback

import yaml
import time
import requests
import allure
import datetime
import decimal

from log.ulog import logger_
from typing import Optional
from requests.adapters import HTTPAdapter
from dateutil.parser import parse
from pathlib import Path
from jsonpath import jsonpath


class Common:

	@staticmethod
	@allure.step("发送请求")
	def response(
			addr: str,
			env: str,
			method: str,
			service: str,
			param: dict,
			headers: dict
	) -> str | dict:
		s = requests.session()
		# 设置请求重试次数
		s.mount("http://", HTTPAdapter(max_retries=3))
		s.mount("https://", HTTPAdapter(max_retries=3))
		url = Common.get_yaml_data("config", "url.yaml")[env][service]
		logger_.info(
			f"请求地址:{url + addr}\n"
			f"请求参数头:{headers}\n"
			f"请求参数:{json.dumps(param, ensure_ascii=False)}"
		)
		if method == "post":
			rep = s.post(
				url=url + addr,
				headers=headers,
				json=json.loads(json.dumps(param, ensure_ascii=False))
			)
			rep.raise_for_status()
			logger_.info(f"响应结果:{rep.text}")
			Common.get_rep_text(rep.text)
			return json.loads(rep.text)
		elif method == "get":
			rep = s.get(
				url=url + addr,
				headers=headers,
				params=param
			)
			rep.raise_for_status()
			try:
				logger_.info(f"响应结果:{rep.text}")
			except Exception:
				logger_.error("响应结果转化异常")
				raise traceback.extract_stack()
			Common.get_rep_text(rep.text)
			try:
				json.loads(rep.text)
				return json.loads(rep.text)
			except Exception:
				return rep.text
		else:
			raise KeyError("不支持的请求类型")

	@staticmethod
	def get_json_data(path: str, filename: str) -> dict:
		"""获取json文件的数据"""
		try:
			file_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + f"/{path}/"
			with open(file_path + filename, 'rb') as f:
				data = json.loads(f.read())
			return data
		except Exception:
			raise

	@staticmethod
	def get_yaml_data(path: str, filename: str) -> dict:
		"""读取yaml文件数据"""
		try:
			with open(Path(__file__).parent.parent / path / filename, 'rb') as f:
				data = f.read()
			_data = yaml.load(data, Loader=yaml.FullLoader)
			return _data
		except Exception:
			raise

	@staticmethod
	@allure.step("返回信息")
	def get_rep_text(rep):
		"""获取请求结果输出报告"""
		pass

	@staticmethod
	def get_date(**kwargs) -> str:
		"""获取格式化后的当前时间
				"""
		if not kwargs.get("types", ""):
			return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
		elif kwargs["types"] == 'day':
			return time.strftime("%Y-%m-%d", time.localtime())

	@staticmethod
	@allure.step("数据加解密")
	def info_crypt(env: str, st: str, is_encrypt: bool = True) -> str:
		"""数据加解密"""
		s = requests.session()
		# 设置请求重试次数
		s.mount("http://", HTTPAdapter(max_retries=3))
		s.mount("https://", HTTPAdapter(max_retries=3))
		json_ = {
			"env": env,
			"data": st
		}
		if is_encrypt is True:
			crypt = "encrypt"
		elif is_encrypt is False:
			crypt = "decrypt"
		else:
			raise ValueError("未知的环境")
		rep = s.post(
			url=f"http://172.17.205.187:9018/support/aes/{crypt}",
			json=json_,
			timeout=5
		)
		rep.raise_for_status()
		reps = json.loads(rep.text)
		Common.get_rep_text(reps)
		return reps["result"]

	@staticmethod
	def date_interval(start_time: str, end_time: str, assert_time: str) -> bool:
		"""判断时间是否在区间内"""
		end_time_date = datetime.datetime.strptime(end_time, "%Y-%m-%d")
		start = parse(start_time)
		if " " in assert_time:
			compare_time = datetime.datetime.strptime(assert_time, "%Y-%m-%d %H:%M:%S")
		else:
			compare_time = datetime.datetime.strptime(assert_time, "%Y-%m-%d")
		end = parse(datetime.datetime.strftime(end_time_date + datetime.timedelta(days=1), "%Y-%m-%d"))
		if start <= compare_time < end:
			return True
		else:
			return False

	@staticmethod
	def get_new_time(when: str, what: str, num: int, times: Optional[str] = "now") -> str:
		"""
		:param times:
		:param when: before or after
		:param what: days,minutes,seconds,hours,weeks
		:param num: 5
		:return: 2020-07-28 11:11:11
		"""
		if times == "now":
			start_time = datetime.datetime.now()
		else:
			pass
		new_times = ''
		if when == "after":
			if what == "days":
				new_times = start_time + datetime.timedelta(days=num)
			elif what == "hours":
				new_times = start_time + datetime.timedelta(hours=num)
			elif what == "seconds":
				new_times = start_time + datetime.timedelta(seconds=num)
			elif what == "minutes":
				new_times = start_time + datetime.timedelta(minutes=num)
			elif what == "weeks":
				new_times = start_time + datetime.timedelta(weeks=num)
		elif when == "before":
			if what == "days":
				new_times = start_time - datetime.timedelta(days=num)
			elif what == "hours":
				new_times = start_time - datetime.timedelta(hours=num)
			elif what == "seconds":
				new_times = start_time - datetime.timedelta(seconds=num)
			elif what == "minutes":
				new_times = start_time - datetime.timedelta(minutes=num)
			elif what == "weeks":
				new_times = start_time - datetime.timedelta(weeks=num)
		return str(new_times).split(".")[0]


class Encoder(json.JSONEncoder):
	"""
	重写json Encoder方法
	date datetime格式化字符串输出
	decimal转为float输出
	"""

	def default(self, o):
		if isinstance(o, datetime.datetime):
			return o.strftime("%Y-%m-%d %H:%M:%S")
		elif isinstance(o, decimal.Decimal):
			return float(o)
		elif isinstance(o, datetime.date):
			return o.strftime("%Y-%m-%d")
		else:
			return json.JSONEncoder.default(self, o)
